package org.sqlproc.sample.tutorial.model;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.PrePersist;
import javax.persistence.Table;

import org.hibernate.annotations.ForeignKey;
import org.hibernate.util.EqualsHelper;
import org.hibernate.validator.constraints.NotEmpty;

/**
*
* Value object representing MediaCharacter.
*/
@Entity
@Table(name = "MEDIACHARACTER")
//@EntityListeners({org.hibernate.validator.event.JPAValidateListener.class
//})
public class MediaCharacter {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID")
    private Long id;
    @Column(name = "NAME", nullable = false, length = 100)
    @NotEmpty
    private String name;
    @Column(name = "UUID", nullable = false, length = 255, unique = true)
    private String uuid;
    @ManyToMany()
    @JoinTable(name = "MEDIACHARACTER_PLAYEDBY", joinColumns =  {
        @JoinColumn(name = "MEDIACHARACTER")
    }
    , inverseJoinColumns =  {
        @JoinColumn(name = "PLAYEDBY")
    }
    )
    @ForeignKey(name = "FK_MEDIACHARACTER_PLAYEDBY_MEDIACHARACTER", inverseName = "FK_MEDIACHARACTER_PLAYEDBY_PLAYEDBY")
    @NotEmpty
    private Set<Person> playedBy = new HashSet<Person>();
    @ManyToMany(mappedBy = "mediaCharacters")
    @NotEmpty
    private Set<Media> existsInMedia = new HashSet<Media>();

    public MediaCharacter() {
    }

    public MediaCharacter(String name) {
        super();
//        Validate.notNull(name);
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    /**
     * The id is not intended to be changed or assigned manually, but
     * for test purpose it is allowed to assign the id.
     */
    protected void setId(Long id) {
        if ((this.id != null) && !this.id.equals(id)) {
            throw new IllegalArgumentException(
                "Not allowed to change the id property.");
        }
        this.id = id;
    }

    public String getName() {
        return name;
    }

    /**
     * Creates a copy of this instance, but with another name.
     */
    public MediaCharacter withName(String name) {
        if (EqualsHelper.equals(name, getName())) {
            return this;
        }
        return new MediaCharacter(name);
    }

    /**
     * This domain object doesn't have a natural key
     * and this random generated identifier is the
     * unique identifier for this domain object.
     */
    public String getUuid() {

        // lazy init of UUID
        if (uuid == null) {
            uuid = java.util.UUID.randomUUID().toString();
        }
        return uuid;
    }

    @SuppressWarnings("unused")
    @PrePersist
    private void initUuid() {
        getUuid();
    }

    public Set<Person> getPlayedBy() {
        return playedBy;
    }

    /**
     * Adds an object to the unidirectional to-many
     * association.
     * It is added the collection {@link #getPlayedBy}.
     */
    public void addPlayedBy(Person playedByElement) {
        this.playedBy.add(playedByElement);
    }

    /**
     * Removes an object from the unidirectional to-many
     * association.
     * It is removed from the collection {@link #getPlayedBy}.
     */
    public void removePlayedBy(Person playedByElement) {
        this.playedBy.remove(playedByElement);
    }

    /**
     * Removes all object from the unidirectional
     * to-many association.
     * All elements are removed from the collection {@link #getPlayedBy}.
     */
    public void removeAllPlayedBy() {
        this.playedBy.clear();
    }

    public Set<Media> getExistsInMedia() {
        return existsInMedia;
    }

    /**
     * Adds an object to the bidirectional many-to-many
     * association in both ends.
     * It is added the collection {@link #getExistsInMedia}
     * at this side and to the collection
     * {@link org.fornax.cartridges.sculptor.examples.library.media.domain.Media#getMediaCharacters}
     * at the opposite side.
     */
    public void addExistsInMedia(Media existsInMediaElement) {
        this.existsInMedia.add(existsInMediaElement);
        existsInMediaElement.getMediaCharacters().add((MediaCharacter) this);
    }

    /**
     * Removes an object from the bidirectional many-to-many
     * association in both ends.
     * It is removed from the collection {@link #getExistsInMedia}
     * at this side and from the collection
     * {@link org.fornax.cartridges.sculptor.examples.library.media.domain.Media#getMediaCharacters}
     * at the opposite side.
     */
    public void removeExistsInMedia(Media existsInMediaElement) {
        this.existsInMedia.remove(existsInMediaElement);
        existsInMediaElement.getMediaCharacters().remove((MediaCharacter) this);
    }

    /**
     * Removes all object from the bidirectional
     * many-to-many association in both ends.
     * All elements are removed from the collection {@link #getExistsInMedia}
     * at this side and from the collection
     * {@link org.fornax.cartridges.sculptor.examples.library.media.domain.Media#getMediaCharacters}
     * at the opposite side.
     */
    public void removeAllExistsInMedia() {
        for (Media d : this.existsInMedia) {
            d.getMediaCharacters().remove((MediaCharacter) this);
        }
        this.existsInMedia.clear();

    }

    /**
     * This method is used by equals and hashCode.
     * @return {{@link #getUuid}
     */
    public Object getKey() {
        return getUuid();
    }
}
